/*
Copyright [2020] [https://www.xiaonuo.vip]

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

  http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：

1.请不要删除和修改根目录下的LICENSE文件。
2.请不要删除和修改Snowy源码头部的版权声明。
3.请保留源码和相关描述文件的项目出处，作者声明等。
4.分发源码时候，请注明软件出处 https://gitee.com/xiaonuobase/snowy
5.在修改包名，模块名称，项目代码等时，请注明软件出处 https://gitee.com/xiaonuobase/snowy
6.若您的项目无法满足以上几点，可申请商业授权，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.modular.cusinfor.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sun.star.uno.Exception;
import vip.xiaonuo.core.exception.ServiceException;
import vip.xiaonuo.core.factory.PageFactory;
import vip.xiaonuo.core.pojo.page.PageResult;
import vip.xiaonuo.core.util.PoiUtil;
import vip.xiaonuo.modular.cusinfor.Result.CusInforResult;
import vip.xiaonuo.modular.cusinfor.entity.CusInfor;
import vip.xiaonuo.modular.cusinfor.enums.CusInforExceptionEnum;
import vip.xiaonuo.modular.cusinfor.mapper.CusInforMapper;
import vip.xiaonuo.modular.cusinfor.param.CusInforParam;
import vip.xiaonuo.modular.cusinfor.service.CusInforService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import vip.xiaonuo.modular.cusperson.entity.CusPerson;
import vip.xiaonuo.modular.cusperson.service.CusPersonService;
import vip.xiaonuo.modular.cussort.service.CusSortService;
import vip.xiaonuo.modular.task.enums.TaskExceptionEnum;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 客户资料service接口实现类
 *
 * @author czw
 * @date 2022-07-20 11:37:49
 */
@Service
public class CusInforServiceImpl extends ServiceImpl<CusInforMapper, CusInfor> implements CusInforService {
    @Resource
    CusSortService cusSortService;
    @Resource
    CusPersonService cusPersonService;


    @Override
    public PageResult<CusInforResult> page(CusInforParam cusInforParam) {
        //sql表名，作为sql语句的一部分
        final String sqlTableName = "n.cus_sort_id";
        QueryWrapper<CusInforResult> queryWrapper = new QueryWrapper<>();
        if (ObjectUtil.isNotNull(cusInforParam)) {

            // 根据客户资料名称 查询
            if (ObjectUtil.isNotEmpty(cusInforParam.getCusInforName())) {
                queryWrapper.lambda().like(CusInfor::getCusInforName, cusInforParam.getCusInforName());
            }
            // 根据社会统一信用代码 查询
            if (ObjectUtil.isNotEmpty(cusInforParam.getCode())) {
                queryWrapper.lambda().like(CusInfor::getCode, cusInforParam.getCode());
            }
            // 根据备注信息 查询
            if (ObjectUtil.isNotEmpty(cusInforParam.getRemark())) {
                queryWrapper.like("n.remark", cusInforParam.getRemark());
            }
            // 根据客户类型 查询
            if (ObjectUtil.isNotEmpty(cusInforParam.getCusSortId())) {
                List<Long> childIdList = cusSortService.getChildIdListById(cusInforParam.getCusSortId());
                if (!childIdList.isEmpty()) {
                    queryWrapper.nested(item -> item.eq(sqlTableName, cusInforParam.getCusSortId()).or().in(sqlTableName, childIdList));
                } else {
                    queryWrapper.eq(sqlTableName, cusInforParam.getCusSortId());
                }

            }
        }
        queryWrapper.orderByDesc("n.create_time");
        return new PageResult<>(baseMapper.page(PageFactory.defaultPage(), queryWrapper));
    }

    @Override
    public List<CusInfor> list(CusInforParam cusInforParam) {
        return this.list();
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(CusInforParam cusInforParam) {
        /*
         *  ================================= 客户资料数据处理 start =================================
         */
        //校验参数，检查是否存在相同的名称
        checkParam(cusInforParam, false);
        //社会统一信用代码校验
        checkUscc(cusInforParam.getCode());
        CusInfor cusInfor = new CusInfor();
        BeanUtil.copyProperties(cusInforParam, cusInfor);
        this.save(cusInfor);
        /*
         *  ================================= 客户资料数据处理 end =================================
         */
        /*
         *  ================================= 联系人数据处理 start =================================
         */
        if (ObjectUtil.isNotEmpty(cusInforParam.getCusPersonList())){
            List<CusPerson>cusPersonList= cusInforParam.getCusPersonList();
            cusPersonList.forEach(cusPerson ->{
                // 设置客户资料id
                if(ObjectUtil.isEmpty(cusPerson.getCusInforId())){
                    cusPerson.setCusInforId(cusInfor.getId());
                }
                  //校验客户资料名称和联系人不能为空
                if(ObjectUtil.isEmpty(cusPerson.getCusInforId())){
                    throw new ServiceException(CusInforExceptionEnum.NOT_NULL_CUS_INFOR_ID);
                }
                if(ObjectUtil.isEmpty(cusPerson.getCusPerson())){
                    throw new ServiceException(CusInforExceptionEnum.NOT_NULL_CUS_PERSON);
                }
            });
            cusPersonService.saveBatch(cusPersonList);
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<CusInforParam> cusInforParamList) {
        // 查询出所有的联系人
        List<CusPerson> cusPeople = cusPersonService.list();
        // 将联系人按照客户资料进行分组
        Map<Long,List<CusPerson>> cusPersonGroupByWorkOrderId = cusPeople.stream()
                .collect(Collectors.groupingBy(CusPerson::getCusInforId));
        if (ObjectUtil.isEmpty(cusInforParamList)){
            return;
        }
        List<Long>cusInforIds=new ArrayList<>();
        List<Long>personIds=new ArrayList<>();
        cusInforParamList.forEach(cusInforParam -> {
            cusInforIds.add(cusInforParam.getId());
            List<CusPerson>cusPersonList=cusPersonGroupByWorkOrderId.get(cusInforParam.getId());
            if (ObjectUtil.isNotEmpty(cusPersonList)){
                cusPersonList.forEach(cusPerson ->{
                    personIds.add(cusPerson.getId());
                });
            }
        });
        this.removeByIds(cusInforIds);
        cusPersonService.removeByIds(personIds);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(CusInforParam cusInforParam) {
        /*
         *  ================================= 客户资料数据处理 start =================================
         */
        //校验参数，检查是否存在相同的名称
        checkParam(cusInforParam, true);
        //社会统一信用代码校验
        checkUscc(cusInforParam.getCode());
        CusInfor cusInfor = this.queryCusInfor(cusInforParam);
        BeanUtil.copyProperties(cusInforParam, cusInfor);
        this.updateById(cusInfor);
        /*
         *  ================================= 客户资料数据处理 end =================================
         */
        /*
         *  ================================= 联系人数据处理 start =================================
         */

        // 联系人map数据准备（防止循环调用sql）
        Map<Long,CusPerson> dbCusPersonMap = new HashMap<>();
        cusPersonService.list().forEach(item->{
            dbCusPersonMap.put(item.getId(), item);
        });

        // 定义新增、编辑容器
        List<CusPerson> addPersonList = new ArrayList<>();
        List<CusPerson> editPersonList = new ArrayList<>();
        List<Long> editPersonIdList = new ArrayList<>();

        // 无id则为新增，有id则为编辑
        List<CusPerson> paramPersonList = cusInforParam.getCusPersonList();
        if(ObjectUtil.isNotEmpty(paramPersonList)){
            paramPersonList.forEach(item->{
                if(ObjectUtil.isEmpty(item.getId())){
                    addPersonList.add(item);
                } else {
                    editPersonList.add(item);
                    editPersonIdList.add(item.getId());
                }
            });
        }


        // 数据库中不在编辑id容器中的，就是要被删除的
        QueryWrapper<CusPerson> queryWrapper = new QueryWrapper<>();
        queryWrapper.lambda().eq(CusPerson::getCusInforId, cusInfor.getId());
        if(ObjectUtil.isNotEmpty(editPersonList)){
            queryWrapper.lambda().notIn(CusPerson::getId, editPersonIdList);
        }
        List<CusPerson> delPersonList = cusPersonService.list(queryWrapper);


        // 批量新增以及数据初始化
        if(ObjectUtil.isNotEmpty(addPersonList)){
            // 将联系人list遍历设置客户资料id
            addPersonList.forEach(item->{
                item.setCusInforId(cusInfor.getId());

            });
            cusPersonService.saveBatch(addPersonList);

        }

        // 批量更新联系人数据（注意：防止有字段支持空更新）
        if(ObjectUtil.isNotEmpty(editPersonList)){
            List<CusPerson> dbEditPersonList = new ArrayList<>();
            editPersonList.forEach(item->{
                // 设置客户资料id
                item.setCusInforId(cusInfor.getId());
                // 防止有字段支持空更新
                if (ObjectUtil.isNotEmpty(item.getId())){
                    CusPerson dbPerson = dbCusPersonMap.get(item.getId());
                    if (ObjectUtil.isNull(dbPerson)) {
                        throw new ServiceException(TaskExceptionEnum.NOT_EXIST);
                    }
                    BeanUtil.copyProperties(item, dbPerson);
                    dbEditPersonList.add(dbPerson);
                }

            });
            cusPersonService.updateBatchById(dbEditPersonList);
        }


        // 执行联系人的批量删除以及关联数据
        if(ObjectUtil.isNotEmpty(delPersonList)){
            List<Long> delPersonIdList = new ArrayList<>();
            delPersonList.forEach(item->{
                delPersonIdList.add(item.getId());
            });
            // 批量删除联系人
            cusPersonService.removeByIds(delPersonIdList);
        }
        /*
         *  ================================= 联系人数据处理 end =================================
         */
    }

    @Override
    public CusInfor detail(CusInforParam cusInforParam) {
        return this.queryCusInfor(cusInforParam);
    }

    /**
     * 获取客户资料
     *
     * @author czw
     * @date 2022-07-20 11:37:49
     */
    private CusInfor queryCusInfor(CusInforParam cusInforParam) {
        CusInfor cusInfor = this.getById(cusInforParam.getId());
        if (ObjectUtil.isNull(cusInfor)) {
            throw new ServiceException(CusInforExceptionEnum.NOT_EXIST);
        }
        return cusInfor;
    }

    @Override
    public void export(CusInforParam cusInforParam) {
        List<CusInfor> list = this.list(cusInforParam);
        PoiUtil.exportExcelWithStream("SnowyCusInfor.xls", CusInfor.class, list);
    }

    /**
     * 校验参数，检查是否存在相同的名称
     *
     * @author xuyuxiang
     * @date 2020/3/25 21:23
     */
    private void checkParam(CusInforParam cusInforParam, boolean isExcludeSelf) {
        Long id = cusInforParam.getId();
        String name = cusInforParam.getCusInforName();
        String code= cusInforParam.getCode();
        LambdaQueryWrapper<CusInfor> queryWrapperByName = new LambdaQueryWrapper<>();
        queryWrapperByName.eq(CusInfor::getCusInforName, name);
        LambdaQueryWrapper<CusInfor> queryWrapperByCode = new LambdaQueryWrapper<>();
        queryWrapperByCode.eq(CusInfor::getCode, code);
        //如果是编辑，校验名称编码时排除自身
        if (isExcludeSelf) {
            queryWrapperByName.ne(CusInfor::getId, id);
        }
        int countByName = this.count(queryWrapperByName);
        int countByCode=this.count(queryWrapperByCode);
        if (countByName >= 1) {
            throw new ServiceException(1, "客户名称重复，请检查名称参数");
        }
        if(countByCode >=1){
            throw new ServiceException(2, "社会统一信用编码重复，请检查编码参数");
        }

    }
    /**
     * 校验参数，检查社会统一信用代码
     *
     * @author czw
     * @date 2022-7-25 15:39
     */
    public static boolean checkUscc(String testUscc)
    {
        if(testUscc.length()!=18)
        {
            throw new ServiceException(1,"统一社会信用代码长度错误");
        }
        //用于存放权值
        int[] weight = {1,3,9,27,19,26,16,17,20,29,25,13,8,24,10,30,28};
        //用于计算当前判断的统一社会信用代码位数
        int index;
        //用于存放当前位的统一社会信用代码
        char testc;
        //用于存放代码字符和加权因子乘积之和
        int tempSum=0;
        int tempNum;
        for(index = 0;index<= 16 ;index++)
        {
            testc=testUscc.charAt(index);

            if(index==0)
            {
                if(testc!='1'&&testc!='5'&&testc!='9'&&testc!='Y')
                {
                    throw new ServiceException(2,"统一社会信用代码中登记管理部门代码错误");
                }
            }

            if(index==1)
            {
                if(testc!='1'&&testc!='2'&&testc!='3'&&testc!='9')
                {
                    throw new ServiceException(3,"统一社会信用代码中机构类别代码错误");
                }
            }

            tempNum=charToNum(testc);
            //验证代码中是否有错误字符
            if(tempNum!=-1)
            {
                tempSum+=weight[index]*tempNum;
            }
            else
            {
                throw new ServiceException(4,"统一社会信用代码中出现错误字符");
            }
        }
        tempNum=31-tempSum%31;
        if(tempNum== 31){  tempNum=0;}
        //按照GB/T 17710标准对统一社会信用代码前17位计算校验码，并与第18位校验位进行比对
        if(charToNum(testUscc.charAt(17))==tempNum){
            return true;
        }
        else{
            return false;
        }

    }

    public static int charToNum(char c)
    {
        switch (c)
        {
            case '0':
                return 0;
            case '1':
                return 1;
            case '2':
                return 2;
            case '3':
                return 3;
            case '4':
                return 4;
            case '5':
                return 5;
            case '6':
                return 6;
            case '7':
                return 7;
            case '8':
                return 8;
            case '9':
                return 9;
            case 'A':
                return 10;
            case 'B':
                return 11;
            case 'C':
                return 12;
            case 'D':
                return 13;
            case 'E':
                return 14;
            case 'F':
                return 15;
            case 'G':
                return 16;
            case 'H':
                return 17;
            case 'J':
                return 18;
            case 'K':
                return 19;
            case 'L':
                return 20;
            case 'M':
                return 21;
            case 'N':
                return 22;
            case 'P':
                return 23;
            case 'Q':
                return 24;
            case 'R':
                return 25;
            case 'T':
                return 26;
            case 'U':
                return 27;
            case 'W':
                return 28;
            case 'X':
                return 29;
            case 'Y':
                return 30;
            default:
                return -1;
        }
    }


}